#include "../include/MyTcpServerSocket.hpp"

static int pipefd[2];
static int epollfd;

void SigHandler(int p_sig)
{
    int save_errno = errno;
    int msg = p_sig;
    send(pipefd[1],(char*)&msg,1,0);
    errno = save_errno;
}

void AddSig(int p_sig)
{
    struct sigaction sa;
    memset(&sa,'\0',sizeof(sa));
    sa.sa_handler = SigHandler;
    sa.sa_flags |= SA_RESTART;
    sigfillset(&sa.sa_mask);
    assert(sigaction(p_sig,&sa,NULL)!=-1);
}

void TimeoutCallBack(std::shared_ptr<ClientData> p_userdata)
{
    epoll_ctl(epollfd,EPOLL_CTL_DEL,p_userdata->sockfd,0);
    close(p_userdata->sockfd);
    printf("close client [%d]\n",p_userdata->sockfd);
}

MyTcpServerSock::MyTcpServerSock(const char* p_ip,int p_port): TcpServerSock(p_ip,p_port),m_users(FD_LIMIT,std::make_shared<ClientData>())
{
    epollfd = epoll_create(5);
    assert(epollfd != -1);
    AddFd(epollfd,m_sockfd);

    int ret = socketpair(PF_UNIX,SOCK_STREAM,0,pipefd);
    assert(ret != -1);
    SetNoBlocking(pipefd[1]);
    AddFd(epollfd,pipefd[0]);

    // 设置信号处理函数
    AddSig(SIGALRM);
    AddSig(SIGTERM);

    m_serverStop = false;
    m_timeout = false;

    // 定时
    alarm(TIMESOLT);
}

MyTcpServerSock::~MyTcpServerSock()
{
    close(m_sockfd);
    close(pipefd[0]);
    close(pipefd[1]);
}


void MyTcpServerSock::Update()
{
    int number = epoll_wait(epollfd,m_events,MAX_EVENTS_NUM,-1);
    if(number < 0 && errno != EINTR)
    {
        printf("Epoll Failure\n");
        return;
    }
    for (int i = 0; i < number; i++)
    {
        int fd = m_events[i].data.fd;
        if(fd == m_sockfd)
        {
            sockaddr_in clientAddr;
            socklen_t clientAddrLen;
            int connfd = accept(m_sockfd,(sockaddr*)&clientAddr,&clientAddrLen);
            assert(connfd != -1);
            AddFd(epollfd,connfd);
            m_users[connfd]->address = clientAddr;
            m_users[connfd]->sockfd = connfd;
            // 创建定时器
            std::shared_ptr<util_time> timer(new util_time());
            timer->user_data = m_users[connfd];
            time_t cur = time(NULL);
            timer->exprie = cur + 3 * TIMESOLT;
            timer->cb_func = TimeoutCallBack;
            m_users[connfd]->timer = timer;
            m_timer_list.add_timer(timer);
            printf("Welcome new client add with id = [%d]\n",connfd);
        }else if(pipefd[0] == fd && (m_events[i].events & EPOLLIN))
        {
            int sig = 0;
            char signals[1024];
            int ret = recv(pipefd[0],signals,sizeof(signals),0);
            if(ret < 0)
            {
                continue;
            }else if(ret == 0)
            {
                continue;
            }else
            {
                for(int i=0;i<ret;++i)
                {
                    switch(signals[i])
                    {
                        case SIGALRM:
                            m_timeout = true;
                            break;
                        case SIGTERM:
                            m_serverStop = true;
                            break;
                        default:
                            break;
                    }
                }
            }
        }else if(m_events[i].events & EPOLLIN)
        {
            memset(m_users[fd]->readBuf,'\0',BUF_SIZE);
            int ret = recv(fd,m_users[fd]->readBuf,BUF_SIZE,0);
            assert(ret != -1);
            printf("get [%d] bytes [%s] data form [%d]\n",ret,m_users[fd]->readBuf,fd);
            auto timer = m_users[fd]->timer;
            if(ret < 0)
            {
                if(errno != EAGAIN)
                {
                    timer->cb_func(m_users[fd]);
                    m_timer_list.del_timer(timer);
                }
            }else if(ret == 0)
            {
                timer->cb_func(m_users[fd]);
                m_timer_list.del_timer(timer);
            }else
            {
                time_t cur = time(NULL);
                timer->exprie = cur + 3 * TIMESOLT;
                printf("adjust time once\n");
                m_timer_list.adjust_timer(timer);
            }
        }

        if(m_timeout)
        {
            TimerHandler();
            alarm(TIMESOLT);
        }
    }
}

void MyTcpServerSock::TimerHandler()
{
    m_timer_list.tick();
    m_timeout = false;
}